package models;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Page;
import play.data.validation.Constraints;
import play.db.ebean.Model;

/**
 * Modele de la classe QCM.
 * 
 * @author ProjetSI-QCM
 * 
 */
@SuppressWarnings("serial")
@Entity
public class Qcm extends Model {
    /**
     * Identifiant du QCM.
     */
    @Id
    private Long idQcm;
    /**
     * Référence vers l'Utilisateur qui a créé le QCM.
     */
    private Utilisateur utilisateur;

    /**
     * Libellé du QCM (Titre).
     */
    @Constraints.Required
    private String libelle;

    /**
     * Date de Création du QCM.
     */
    private Date dateCreation;

    /**
     * Date d'ouverture du QCM.
     */
    @Constraints.Required
    private Date dateOuverture;

    /**
     * Date de clôture du QCM.
     */
    @Constraints.Required
    private Date dateCloture;

    /**
     * True = les étudiants peuvent voir leur notes et la correction. False =
     * les étudiants ne peuvent voir leur notes et la correction.
     */
    private boolean estPublie = false;

    /**
     * Clé permettant de passer le QCM.
     */
    private String cleAuthentification;
    /**
     * Liste des questions associées au QCM.
     */
    private List<Question> listeQuestions = new ArrayList<Question>();
    /**
     * Liste des Points positifs et négatifs associés à chaque niveau de
     * Question.
     */
    private List<QcmNiveauquestion> listeNiveauQuestions = 
            new ArrayList<QcmNiveauquestion>();

    /**
     * Finder de la classe QCM.
     */
    private static Finder<Long, Qcm> find = new Finder<Long, Qcm>(Long.class,
            Qcm.class);

    /**
     * La méthode permet de retrouver un QCM à partir de son ID.
     * 
     * @param id
     *            Identifiant du QCM.
     * @return Qcm L'objet QCM.
     */
    public static Qcm findById(final Long id) {
        return Ebean.find(Qcm.class, id);
    }

    /**
     * Permet de récupérer la Liste de tous les QCM créés.
     * 
     * @return List<Qcm> La liste des QCM créés.
     */
    public static List<Qcm> findAll() {
        return find.all();
    }

    /**
     * Liste des options pour les listes déroulantes.
     * 
     * @return Map<String,String>
     */
    public static Map<String, String> options() {
        final LinkedHashMap<String, String> options = 
                new LinkedHashMap<String, String>();
        for (Qcm c : Qcm.find.orderBy("idQcm").findList()) {
            options.put(c.getIdQcm().toString(), c.getLibelle().toString());
        }
        return options;
    }

    /**
     * Permet de récupérer le statut du QCM en fonction de la date. A venir :
     * date courante < date d'ouverture Ouvert : date d'ouverture <= date
     * courante < date de clôture Clos : date de clôture <= date courante
     * 
     * @return Le statut sous la forme d'une chaîne de caractères.
     */
    public final String getStatut() {
        final Date now = new Date();
        String statut;
        if (now.compareTo(dateCloture) > 0) {
            statut = "Clos";
        } else if (now.compareTo(dateOuverture) < 0) {
            statut = "A venir";
        } else {
            statut = "Ouvert";
        }
        return statut;
    }

    /**
     * Retourne, pour un NiveauQuestion donné, le QcmNiveauquestion associé.
     * 
     * @param nq
     *            Le NiveauQuestion recherché
     * @return nivq l'objet QcmNiveauquestion associé au QCM pour ce
     *         NiveauQuestion
     */
    public final QcmNiveauquestion findQcmNiveauQuestion(
            final NiveauQuestion nq) {
        for (QcmNiveauquestion nivq : listeNiveauQuestions) {
            if (nivq.getNiveauQuestion().equals(nq)) {
                return nivq;
            }
        }
        return null;
    }

    /**
     * Permet de sauvegarder un objet en Base de Données.
     * 
     * @param qcm
     *            Objet a sauvegarder
     */
    public static void create(final Qcm qcm) {
        qcm.save();
    }

    /**
     * Permet de mettre à jour un objet en Base de Données.
     * 
     * @param qcm
     *            Objet à Sauvegarder
     */
    public static void update(final Qcm qcm) {
        qcm.update();
    }

    /**
     * Permet de supprimer un objet de la Base de Données.
     * 
     * @param id
     *            Identifiant de l'objet à supprimer
     */
    public static void delete(final Long id) {
        final Qcm qcm = Qcm.findById(id);

		for (UtilisateurQcm utilisateurqcm : UtilisateurQcm.findAllByIdQcm(id)) {
			UtilisateurQcm.delete(utilisateurqcm.getIdUtilisateurQcm());
		}
		for (QcmNiveauquestion qnq : qcm.getListeNiveauQuestions()) {
			QcmNiveauquestion.delete(qnq.getIdQcmNiveauQuestion());
		}
		find.ref(id).delete();
	}

    /**
     * Retourne une Page de Qcm.
     * 
     * @param page
     *            Page à afficher
     * @param pageSize
     *            Nombre d'objets par page
     * @param sortBy
     *            Propriété utilisée pour le tri
     * @param order
     *            Sens du tri (asc ou desc)
     * @param filter
     *            Filtre appliqué sur le nom de la colonne
     * @return Page<Qcm> la page
     */
    public static Page<Qcm> page(final int page, final int pageSize,
            final String sortBy, final String order, final String filter) {
        return find.where().ilike("idQcm", "%" + filter + "%")
                .orderBy(sortBy + " " + order).fetch("utilisateur")
                .findPagingList(pageSize).setFetchAhead(false).getPage(page);
    }

	/**
	 * @return the idQcm
	 */
	public final Long getIdQcm() {
		return idQcm;
	}

	/**
	 * @param id the idQcm to set
	 */
	public final void setIdQcm(final Long id) {
		this.idQcm = id;
	}

	/**
	 * @return the utilisateur
	 */
	@ManyToOne
	public final Utilisateur getUtilisateur() {
		return utilisateur;
	}

	/**
	 * @param u the utilisateur to set
	 */
	public final void setUtilisateur(final Utilisateur u) {
		this.utilisateur = u;
	}

	/**
	 * @return the libelle
	 */
	public final String getLibelle() {
		return libelle;
	}

	/**
	 * @param l the libelle to set
	 */
	public final void setLibelle(final String l) {
		this.libelle = l;
	}

	/**
	 * @return the dateCreation
	 */
	public final Date getDateCreation() {
		return dateCreation;
	}

	/**
	 * @param date the dateCreation to set
	 */
	public final void setDateCreation(final Date date) {
		this.dateCreation = date;
	}

	/**
	 * @return the dateOuverture
	 */
	public final Date getDateOuverture() {
		return dateOuverture;
	}

	/**
	 * @param date the dateOuverture to set
	 */
	public final void setDateOuverture(final Date date) {
		this.dateOuverture = date;
	}

	/**
	 * @return the dateCloture
	 */
	public final Date getDateCloture() {
		return dateCloture;
	}

	/**
	 * @param date the dateCloture to set
	 */
	public final void setDateCloture(final Date date) {
		this.dateCloture = date;
	}

	/**
	 * @return the estPublie
	 */
	public final boolean getEstPublie() {
		return estPublie;
	}

	/**
	 * @param b the estPublie to set
	 */
	public final void setEstPublie(final boolean b) {
		this.estPublie = b;
	}

	/**
	 * @return the cleAuthentification
	 */
	public final String getCleAuthentification() {
		return cleAuthentification;
	}

	/**
	 * @param cle the cleAuthentification to set
	 */
	public final void setCleAuthentification(final String cle) {
		this.cleAuthentification = cle;
	}

	/**
	 * @return the listeQuestions
	 */
	@ManyToMany(cascade = CascadeType.ALL)
	public final List<Question> getListeQuestions() {
		return listeQuestions;
	}

	/**
	 * @param liste the listeQuestions to set
	 */
	public final void setListeQuestions(final List<Question> liste) {
		this.listeQuestions = liste;
	}

	/**
	 * @return the listeNiveauQuestions
	 */
	@OneToMany(cascade = CascadeType.ALL)
	public final List<QcmNiveauquestion> getListeNiveauQuestions() {
		return listeNiveauQuestions;
	}

	/**
	 * @param liste the listeNiveauQuestions to set
	 */
	public final void setListeNiveauQuestions(
			final List<QcmNiveauquestion> liste) {
		this.listeNiveauQuestions = liste;
	}

    
}
